/**
 * @author Jordan Barroga
 * @author Reed Pasatiempo
 */

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.awt.geom.Dimension2D;

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

public class SettingsMenu implements ActionListener
{
	static Settings temp;

	JFrame frame;
	
	static final int jSliderMin = 1;
	static final int jSliderMax = 4;
	static final int jSliderInit = 1;
	
	JRadioButton cyan = new JRadioButton("Cyan");
	JRadioButton blue = new JRadioButton("Blue");
	JRadioButton darkGray = new JRadioButton("Dark Gray");
	JRadioButton gray = new JRadioButton("Gray");
	JRadioButton green = new JRadioButton("Green");
	JRadioButton lightGray = new JRadioButton("Light Gray");
	JRadioButton magenta = new JRadioButton("Magenta");
	JRadioButton orange = new JRadioButton("Orange");
	JRadioButton pink = new JRadioButton("Pink");
	JRadioButton red = new JRadioButton("Red");
	JRadioButton white = new JRadioButton("White");
	JRadioButton yellow = new JRadioButton("Yellow");
	JRadioButton black = new JRadioButton("Black");

	JTextField heightInput = new JTextField(5);
	JTextField widthInput = new JTextField(5);
	JTextField speedInput = new JTextField(5);
	int backgroundColor = 13;
	JSlider difficultyInput = new JSlider(JSlider.HORIZONTAL, jSliderMin, jSliderMax, jSliderInit);
	
	boolean snakeModified = false;
	boolean boardModified = false;
	boolean backgroundModified = false;
	
	/**
	 * Creates the graphics user interface for the settings menu.
	 * @param settings
	 */
	public SettingsMenu(Settings settings)
	{
		temp = settings;
		getDefaultsFromFile();
		
		frame = new JFrame("Settings");
		Container test = frame.getContentPane();
		frame.setSize(500, 200);
		frame.setDefaultCloseOperation(frame.HIDE_ON_CLOSE);
		frame.setVisible(true);
		frame.setResizable(false);
		
		JPanel main = new JPanel();	// Panel that contains the contents
		JPanel exit = new JPanel();	// Panel with exit buttons
		
		JTabbedPane menu = new JTabbedPane();	// Tabbed pane
		main.add(menu);
		
		// Tabbed Panels
		JPanel snake = new JPanel();
		snake.setSize(300,400);
		JPanel board = new JPanel();
		board.setSize(300, 400);
		JPanel bg = new JPanel();
		bg.setSize(300, 400);
		
		// Tabbed Menu
		menu.addTab("Snake", snake);
		menu.addTab("Board", board);
		JPanel bgPanel = new JPanel(new GridLayout(3, 0));
		menu.add(bgPanel);
		bgPanel.setSize(300, 400);
		menu.addTab("Background", bgPanel);
		
		//==========================
		// TABBED SNAKE
		//==========================
		JLabel speedLabel = new JLabel("Speed: ");
		snake.add(speedLabel);
		speedInput.getDocument().addDocumentListener(new DocumentListener()
		{
			public void changedUpdate(DocumentEvent e)
			{
				snakeModified = true;
			}
			public void removeUpdate(DocumentEvent e)
			{
				snakeModified = true;
			}
			public void insertUpdate(DocumentEvent e)
			{
				snakeModified = true;
			}
		});
		snake.add(speedInput);
		JLabel difficultyLabel = new JLabel("Difficulty: ");
		snake.add(difficultyLabel);
		snake.add(difficultyInput);
		difficultyInput.setPaintLabels(true);
		difficultyInput.setPaintTicks(true);
		difficultyInput.setMinorTickSpacing(1);
		difficultyInput.setMajorTickSpacing(1);
		
		//==========================
		// TABBED BOARD
		//==========================
		JLabel heightLabel = new JLabel("Height: ");
		board.add(heightLabel);
		board.add(heightInput);
		heightInput.getDocument().addDocumentListener(new DocumentListener()
		{
			public void changedUpdate(DocumentEvent e)
			{
				boardModified = true;
			}
			public void removeUpdate(DocumentEvent e)
			{
				boardModified = true;
			}
			public void insertUpdate(DocumentEvent e)
			{
				boardModified = true;
			}
		});
		JLabel widthLabel = new JLabel("Width: ");
		board.add(widthLabel);
		widthInput.getDocument().addDocumentListener(new DocumentListener()
		{
			public void changedUpdate(DocumentEvent e)
			{
				boardModified = true;
			}
			public void removeUpdate(DocumentEvent e)
			{
				boardModified = true;
			}
			public void insertUpdate(DocumentEvent e)
			{
				boardModified = true;
			}
		});
		board.add(widthInput);
		
		//==========================
		// TABBED BACKGROUND
		//==========================
		// GOTTA "setMnemonic" and "setActionCommand"
		cyan.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{ 
				backgroundColor = 1; 
				backgroundModified = true;
			}
		});
		blue.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				backgroundColor = 2;
				backgroundModified = true;
			}
		});
		darkGray.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				backgroundColor = 3;
				temp.setBackground(3);
			}
		});
		gray.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				backgroundColor = 4;
				backgroundModified = true;
			}
		});
		green.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				backgroundColor = 5;
				backgroundModified = true;
			}
		});
		lightGray.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				backgroundColor = 6;
				backgroundModified = true;
			}
		});
		magenta.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				backgroundColor = 7;
				backgroundModified = true;
			}
		});
		orange.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				backgroundColor = 8;
				backgroundModified = true;
			}
		});
		pink.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				backgroundColor = 9;
				backgroundModified = true;
			}
		});
		red.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				backgroundColor = 10;
				backgroundModified = true;
			}
		});
		white.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				backgroundColor = 11;
				backgroundModified = true;
			}
		});
		yellow.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				backgroundColor = 12;
				backgroundModified = true;
			}
		});
		black.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				backgroundColor = 13;
				backgroundModified = true;
			}
		});
		black.setSelected(true);
		
		// adding to groups keeps multiples from being checked
		ButtonGroup bgGroup = new ButtonGroup();
		bgGroup.add(cyan);
		bgGroup.add(blue);
		bgGroup.add(darkGray);
		bgGroup.add(gray);
		bgGroup.add(green);
		bgGroup.add(lightGray);
		bgGroup.add(magenta);
		bgGroup.add(orange);
		bgGroup.add(pink);
		bgGroup.add(red);
		bgGroup.add(white);
		bgGroup.add(yellow);
		bgGroup.add(black);
		
		// adding them to the panel
		bgPanel.add(cyan);
		bgPanel.add(blue);
		bgPanel.add(darkGray);
		bgPanel.add(gray);
		bgPanel.add(green);
		bgPanel.add(lightGray);
		bgPanel.add(magenta);
		bgPanel.add(orange);
		bgPanel.add(pink);
		bgPanel.add(red);
		bgPanel.add(white);
		bgPanel.add(yellow);
		bgPanel.add(black);
		
		//==========================
		// EXIT PANEL
		//==========================

		JButton save = new JButton("Save Changes");
		save.setToolTipText("Saves the changes made for future use.");
		save.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				boolean result = saveChanges();
				if(result == true)
				{
					writeDefaultsToFile();
					frame.setVisible(false);
				}
				else
				{
					// error messages have already been displayed
					// so what do i do with this?
				}
			}
		});
		// make so button sets isModified to false
		JButton undo = new JButton("Undo Changes");
		undo.setToolTipText("Resets fields to last saved changed settings.");
		undo.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				getDefaultsFromFile();
			}
		});
		JButton def = new JButton("Default");
		def.setToolTipText("Resets the fields to original defaults.");
		def.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				reset();
			}
		});
		JButton leave = new JButton("Exit");
		leave.setToolTipText("Exits out of the settings menu.");
		leave.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				if(!boardModified && !snakeModified && !backgroundModified )
				{
					frame.setVisible(false);
				}
				else
				{
					new ErrorDialog("Exiting", "You cannot exit because changes " +
							"have been detected without saving.");
				}
			}
		});
		
		exit.add(save);
		exit.add(undo);
		exit.add(def);
		exit.add(leave);
		
		Container pane = frame.getContentPane();
		
		pane.setLayout(new BorderLayout());
		frame.add(main);
		frame.add(exit);
		frame.getContentPane().add(main, BorderLayout.NORTH);
		frame.getContentPane().add(exit, BorderLayout.CENTER);
		
	}
	
	// This is just so i do not get an error not implementing a method
	public void actionPerformed(ActionEvent arg0) {	}
	
	/**
	 * Resets all the data fields to last known saved default.
	 */
	private void reset()
	{
		Toolkit tool = Toolkit.getDefaultToolkit();
		Dimension data = tool.getScreenSize();
		
		widthInput.setText(Integer.toString(data.width/2));
		heightInput.setText(Integer.toString(data.height/2));
		speedInput.setText("140");
		difficultyInput.setExtent(1);
		saveChanges();
	}
	
	/**
	 * Checks the changes that have been made to the settings
	 * and determines whether they are valid.
	 */
	private boolean saveChanges()
	{
		boolean error = false;
		
		Toolkit tool = Toolkit.getDefaultToolkit();
		Dimension data = tool.getScreenSize();

		if(snakeModified)
		{
			int spd = Integer.parseInt(speedInput.getText());
			int maxSpeed = 20;
			int minSpeed = 140;
			if(spd < maxSpeed)
			{
				new ErrorDialog("Speed", "Input speed is too high.");
				error = true;
			}
			else if(spd > minSpeed)
			{
				new ErrorDialog("Speed", "Input speed is to slow");
				error = true;
			}
		}
		if(boardModified)
		{
			int hgt = Integer.parseInt(heightInput.getText());
			int maxHeight = data.height;
			int minHeight = 300;
			
			if(hgt > maxHeight)
			{
				new ErrorDialog("Height", "The height that you have enter " +
						"exceeds your screen resolution.\n Please enter a "
						+ "new height that is smaller than " + data.height + ".");
				error = true;
			}
			else if(hgt < minHeight)
			{
				new ErrorDialog("Height", "The height that you have entered is too " +
						"small. Please enter a height that is bigger than " + minHeight + ".");
				error = true;
			}

			int wdth = Integer.parseInt(widthInput.getText());
			int maxWidth = data.width;
			int minWidth = 300;
			
			if(wdth > maxWidth)
			{
				new ErrorDialog("Width", "The width that you have enter " +
						"exceeds your screen resolution.\n Please enter a "
						+ "new width that is smaller than " + data.width + ".");
				error = true;
			}
			else if(wdth < minWidth)
			{
				new ErrorDialog("Width", "The width that you have entered is too " +
						"small. Please enter a width that is bigger than " + minWidth + ".");
				error = true;
			}
		}
		
		if(error == false)
		{
			temp.setBackground(backgroundColor);
			temp.setHeight(Integer.parseInt(heightInput.getText()));
			temp.setWidth(Integer.parseInt(widthInput.getText()));
			temp.setSpeed(Integer.parseInt(speedInput.getText()));
			temp.setDifficulty(difficultyInput.getExtent());
			
			// Display message that changes have been saved!
		}
		
		return error;
	}
	
	/**
	 * creates default settings when no current default settings
	 * exist prior to opening the settings menu.
	 */
	private void createDefaults()
	{
		Toolkit tool = Toolkit.getDefaultToolkit();
		Dimension data = tool.getScreenSize();
		
		System.out.println("createDefaults Called");
		widthInput.setText(Integer.toString(data.width));
		heightInput.setText(Integer.toString(data.height));
		speedInput.setText("140");			// DEFINITELY NEED TO CHANGE THIS
		difficultyInput.setExtent(1);
		writeDefaultsToFile();
		
		System.out.println("finished createDefaults");
	}

	/**
	 * Checks a file that is under a preset name for default fields data.
	 * @return
	 */
	private boolean getDefaultsFromFile()
	{
		boolean error = true;
		
		try
		{
			File inFile = new File("Default.txt");
			FileReader fReader = new FileReader(inFile);
			BufferedReader buff = new BufferedReader(fReader);
			
			heightInput.setText(buff.readLine());
			widthInput.setText(buff.readLine());
			speedInput.setText(buff.readLine());
			difficultyInput.setExtent(Integer.parseInt(buff.readLine()));
			
		}
		catch(NullPointerException e)
		{
			System.out.println("getDefaults: NullPointerException has occurred.");
			createDefaults();
		}
		catch(FileNotFoundException e)
		{
			System.out.println("getDefaults: FileNotFoundException has occurred.");
			createDefaults();
		}
		catch(IOException e)
		{
			System.out.println("getDefaults: IOException has occurred.");
			createDefaults();
		}
		
		return error;
	}
	
	/**
	 * Writes new changes made to a file for future use and
	 * resets all the boolean variables that indicate if fields
	 * have been changed.
	 */
	private void writeDefaultsToFile()
	{
		try
		{
			File inFile = new File("Default.txt");
			FileWriter fwriter = new FileWriter(inFile);
			BufferedWriter buff = new BufferedWriter(fwriter);
			
			buff.write(heightInput.getText());
			buff.write('\n');
			buff.write(widthInput.getText());
			buff.write('\n');
			buff.write(speedInput.getText());
			buff.write('\n');
			buff.write(Integer.toString(difficultyInput.getExtent()));
			buff.write('\n');
			
			buff.close();
			
		}
		catch(IOException e)
		{
			System.out.println("writeChanges: IOException has occurred.");
		}
		
		snakeModified = false;
		boardModified = false;
		backgroundModified = false;
	}
	
	/**
	 * A private class that contains an error dialog that will
	 * be shown if any of the input data contains errors.
	 * @author Jordan Barroga
	 * @author Reed Pasatiempo
	 *
	 */
	private class ErrorDialog
	{
		public ErrorDialog(String title, String message)
		{
			// SHOULD HAVE MORE PARAM INPUTS SO THAT I CAN CUSTOMIZE THE MESSAGE MORE
			JFrame frame = new JFrame();
			JOptionPane.showMessageDialog(frame, message, title, JOptionPane.ERROR_MESSAGE);
			frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
		}
		
	}
	
}
